package com.gitee.apanlh.web.util;

import com.gitee.apanlh.exp.StreamException;
import com.gitee.apanlh.exp.StreamReadException;
import com.gitee.apanlh.spring.ServletBeanUtils;
import com.gitee.apanlh.util.base.ArrayUtils;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.Empty;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.base.MapUtils;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.io.IOUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.gitee.apanlh.web.model.RequestHeader;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

/**	
 * 	Servlet相关
 * 	
 * 	@author Pan
 */
public class ServletUtils {
	
	/**
	 * 	构造函数
	 * 
	 * 	@author Pan
	 */
	private ServletUtils() {
		//	不允许外部实例
		super();
	}
	
	/**	
	 * 	获取HttpServletRequest对象
	 * 	
	 * 	@author Pan
	 * 	@return HttpServletRequest
	 */
	public static HttpServletRequest getRequest() {
		return ServletBeanUtils.getHttpRequest();
	}
	
	/**	
	 * 	获取HttpServletResponse对象
	 * 	
	 * 	@author Pan
	 * 	@return HttpServletRequest
	 */
	public static HttpServletResponse getResponse() {
		return ServletBeanUtils.getHttpResponse();
	}
	
	/**	
	 * 	获取request参数(同参多值则用逗号分割表示)
	 * 	
	 * 	@author Pan
	 * 	@return	Map
	 */
	public static Map<String, String> getParams() {
		return getParams(getRequest());
	}
	
	/**	
	 * 	获取request参数(同参多值则用逗号分割表示)
	 * 	
	 * 	@author Pan
	 * 	@param 	request	HttpServletRequest
	 * 	@return	Map
	 */
	public static Map<String, String> getParams(HttpServletRequest request) {
		Map<String, String[]> parameterMap = request.getParameterMap();
		
		return MapUtils.newHashMap(newMap -> IteratorUtils.entrySet(parameterMap, (key, value) -> {
			if (!ValidParam.isEmpty(value)) {
				for (int i = 0; i < value.length; i++) {
					newMap.put(key, ArrayUtils.join(value, ","));
				}
			}
		}), parameterMap.size());
	}
	
	/**	
	 * 	获取request参数所有的Key值
	 * 	
	 * 	@author Pan
	 * 	@param 	request	HttpServletRequest
	 * 	@return	List
	 */
	public static List<String> getParamKeys(HttpServletRequest request) {
		return CollUtils.newArrayList(request.getParameterNames());
	}

	/**	
	 * 	获取请求头
	 * 	
	 * 	@author Pan
	 * 	@param 	request	HttpServletRequest
	 * 	@param 	key	键
	 * 	@return	String
	 */
	public static String getHeader(HttpServletRequest request, String key) {
		return request.getHeader(key);
	}
	
	/**	
	 * 	获取请求头
	 * 	
	 * 	@author Pan
	 * 	@param 	key	键
	 * 	@return	String
	 */
	public static String getHeader(String key) {
		return getHeader(getRequest(), key);
	}
	
	/**	
	 * 	获取所有请求头
	 * 	
	 * 	@author Pan
	 * 	@return	Map
	 */
	public static Map<String, String> getHeaders() {
		return MapUtils.newHashMap(map -> IteratorUtils.array(getRequest().getHeaderNames(), e -> map.put(e, getHeader(e))));
	}
	
	/**	
	 * 	获取session对象
	 * 	
	 * 	@author Pan
	 * 	@return	HttpSession
	 */
	public static HttpSession getSession() {
        return getRequest().getSession();
    }
	
	/**	
	 * 	获取sessionId
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public static String getSessionId() {
        return getSession().getId();
    }
	
	/**		
	 * 	根据name来获取 cookie
	 * 	
	 * 	@author Pan
	 * 	@param 	key	键
	 * 	@return	Cookie
	 */
	public static Cookie getCookie(String key) {
		HttpServletRequest httpRequest = getRequest();
		Cookie[] cookies = httpRequest.getCookies();
		if (ValidParam.isEmpty(cookies)) {
			return null;
		}
		
		for (int i = 0; i < cookies.length; i++) {
			Cookie cookie = cookies[i];
			if (StringUtils.eq(cookie.getName(), key)) {
				return cookie;
			}
		}
		return null;
	}
	
	/**	
	 * 	获取cookies
	 * 	
	 * 	@author Pan
	 * 	@return	Cookie[]
	 */
	public static Cookie[] getCookies() {
		HttpServletRequest httpRequest = getRequest();
		return httpRequest.getCookies();
	}
	
	/**	
	 * 	获取cookies-Map形式
	 * 	
	 * 	@author Pan
	 * 	@return	Map
	 */
	public static Map<String, String> getCookiesMap() {
		Cookie[] cookies = getCookies();
		if (cookies == null) {
			return Empty.map();
		}
		Map<String, String> newHashMap = MapUtils.newHashMap();
		
		for (int i = 0; i < cookies.length; i++) {
			Cookie cookie = cookies[i];
			newHashMap.put(cookie.getName(), cookie.getValue());
		}
		return newHashMap;
	}
	
	/**	
	 * 	验证是否请求头全为空
	 * 	<br>如果不存在或者值为空 或者null则false
	 * 	
	 * 	@author Pan
	 * 	@param 	key		键
	 * 	@return	boolean
	 */
	public static boolean headerIsAllNotEmpty(String... key) {
		Map<String, String> headers = getHeaders();
		for (int i = 0; i < key.length; i++) {
			String value = headers.get(key[i]);
			if (ValidParam.isEmpty(value)) {
				return false;
			}
		}
		return true;
	}
	
	/**		
	 * 	添加请求头
	 * 	
	 * 	@author Pan
	 * 	@param 	key		键
	 * 	@param 	value	值
	 */
	public static void addHeader(String key, String value) {
		addHeader(ServletBeanUtils.getHttpResponse(), key, value);
	}
	
	/**		
	 * 	添加请求头
	 * 	
	 * 	@author Pan
	 * 	@param 	response	HttpServletResponse对象
	 * 	@param 	key			键
	 * 	@param 	value		值
	 */
	public static void addHeader(HttpServletResponse response, String key, String value) {
		response.addHeader(key, value);
	}
	
	/**	
	 * 	添加请求头
	 * 	
	 * 	@author Pan
	 * 	@param 	response	HttpServletResponse	对象
	 * 	@param 	headers		RequestHeader		对象
	 */
	public static void addHeader(HttpServletResponse response, RequestHeader headers) {
		IteratorUtils.entrySet(headers.getHeaders(), response::addHeader);
	}
	
	/**	
	 * 	添加请求头
	 * 	
	 * 	@author Pan
	 * 	@param 	headers		RequestHeader		对象
	 */
	public static void addHeader(RequestHeader headers) {
		HttpServletResponse httpResponse = ServletBeanUtils.getHttpResponse();
		addHeader(httpResponse, headers);
	}
	
	/**	
	 * 	添加cookie
	 * 	
	 * 	@author Pan
	 * 	@param 	cookie	Cookie
	 */
	public static void addCookie(Cookie cookie) {
		HttpServletResponse httpResponse = ServletBeanUtils.getHttpResponse();
		httpResponse.addCookie(cookie);
	}
	
	/**	
	 * 	移除cookie
	 * 	
	 * 	@author Pan
	 * 	@param 	name	cookie-name
	 */
	public static void removeCookie(String name) {
		Cookie cookie = getCookie(name);
		if (cookie == null) {
			return ;
		}
		cookie.setMaxAge(0);
		addCookie(cookie);
	}
	
	/**
	 * 	移除所有存在的cookie
	 * 	
	 * 	@author Pan
	 */
	public static void removeCookies() {
		Map<String, String> cookiesMap = getCookiesMap();
		if (ValidParam.isEmpty(cookiesMap)) {
			return ;
		}
		IteratorUtils.keySet(cookiesMap, (key, iterator) -> removeCookie(key));
	}
	
	/**	
	 * 	获取请求方法
	 * 	
	 * 	@author Pan
	 * 	@param	request	HttpServletRequest对象
	 * 	@return	String
	 */
	public static String getMethod(HttpServletRequest request) {
		return request.getMethod();
	}
	
	/**	
	 * 	获取请求方法
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public static String getMethod() {
		return getMethod(getRequest());
	}
	
	/**	
	 * 	获取输入流
	 * 	<br>内部捕获异常
	 * 	
	 * 	@author Pan
	 * 	@param 	request	HttpServletRequest对象
	 * 	@return	InputStream
	 */
	public static InputStream getInputStream(HttpServletRequest request) {
		try {
			return request.getInputStream();
		} catch (Exception e) {
			throw new StreamException(e.getMessage(), e);
		}
	}
	
	/**	
	 * 	获取输出流
	 * 	<br>内部捕获异常
	 * 	
	 * 	@author Pan
	 * 	@param 	response	HttpServletResponse对象
	 * 	@return	OutputStream
	 */
	public static OutputStream getOutputStream(HttpServletResponse response) {
		try {
			return response.getOutputStream();
		} catch (Exception e) {
			throw new StreamException(e.getMessage(), e);
		}
	}
	
	/**	
	 * 	读取输入流
	 * 	<br>默认不会关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@return	byte[]
	 */
	public static byte[] read() {
		return read(getRequest(), false);
	}

	/**	
	 * 	读取输入流
	 * 	<br>默认不会关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	request	HttpServletRequest对象
	 * 	@return	byte[]	
	 */
	public static byte[] read(HttpServletRequest request) {
		return read(request, false);
	}
	
	/**	
	 * 	读取输入流
	 * 	<br>自定义关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	request		HttpServletRequest对象
	 * 	@param 	autoClose	true自动关闭流
	 * 	@return	byte[]
	 */
	public static byte[] read(HttpServletRequest request, boolean autoClose) {
		return IOUtils.read(getInputStream(request), autoClose);
	}
	
	/**	
	 * 	读取输入流-字符串形式
	 * 	<br>默认不会关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public static String readString() {
		return readString(getRequest(), false);
	}
	
	/**	
	 * 	读取输入流-字符串形式
	 * 	<br>默认不会关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	request	HttpServletRequest对象
	 * 	@return	String
	 */
	public static String readString(HttpServletRequest request) {
		return readString(request, false);
	}
	
	/**	
	 * 	读取输入流-字符串形式
	 * 	<br>自定义关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	request		HttpServletRequest对象
	 * 	@param 	autoClose	true自动关闭流
	 * 	@return	String
	 */
	public static String readString(HttpServletRequest request, boolean autoClose) {
		return IOUtils.readString(getInputStream(request), autoClose);
	}
	
	/**	
	 * 	获取请求体-字节形式
	 * 	<br>默认不会关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@return	byte[]
	 */
	public static byte[] readBody() {
		return readBody(getRequest(), false);
	}

	/**	
	 * 	获取请求体-字节形式
	 * 	<br>默认不会关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	request	HttpServletRequest对象
	 * 	@return	byte[]	
	 */
	public static byte[] readBody(HttpServletRequest request) {
		return readBody(request, false);
	}
	
	/**	
	 * 	获取请求体-字节形式
	 * 	<br>自定义关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	request		HttpServletRequest对象
	 * 	@param 	autoClose	true自动关闭流
	 * 	@return	byte[]
	 */
	public static byte[] readBody(HttpServletRequest request, boolean autoClose) {
		return readBodyString(request, autoClose).getBytes();
	}
	
	
	/**	
	 * 	获取请求体
	 * 	<br>默认不会关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public static String readBodyString() {
		return readBodyString(getRequest(), false);
	}

	/**	
	 * 	获取请求体
	 * 	<br>默认不会关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	request	HttpServletRequest对象
	 * 	@return	String	
	 */
	public static String readBodyString(HttpServletRequest request) {
		return readBodyString(request, false);
	}
	
	/**	
	 * 	获取请求体
	 * 	<br>自定义关闭HttpServletRequest输入流
	 * 	
	 * 	@author Pan
	 * 	@param 	request		HttpServletRequest对象
	 * 	@param 	autoClose	true自动关闭流
	 * 	@return	String
	 */
	public static String readBodyString(HttpServletRequest request, boolean autoClose) {
		try {
			return IOUtils.readString(request.getReader(), autoClose);
		} catch (Exception e) {
			throw new StreamReadException(e.getMessage(), e);
		}
	}
	
    /**	
     * 	验证是否为Ajax请求
     * 
     * 	@author Pan
     * 	@param 	request	HttpServletRequest对象
     * 	@return	boolean
     */
    public static boolean isAjax(HttpServletRequest request) {
        String accept = request.getHeader("accept");
        if (accept != null && accept.contains("application/json")) {
            return true;
        }

        String xRequestedWith = request.getHeader("X-Requested-With");
        if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) {
            return true;
        }

        String uri = request.getRequestURI();
        if (StringUtils.contains(uri, ".json", ".xml")) {
            return true;
        }

        String ajax = request.getParameter("__ajax");
        return StringUtils.contains(ajax, "json", "xml");
    }
}
